/* Copyright 2017, 2018, 2019, 2020 Gabriel Czernikier
 *
 * This file is part of Côtehaus.
 * Côtehaus is free software: you can redistribute it and/or modify
 * it under the terms of one of the following:
 * 1. The same dual license as that of Côtehaus itself, of which individual licenses are
 * the MIT License and the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 2. The MIT License.
 * 3. The GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * Côtehaus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * MIT License and the GNU General Public License for more details.
 * You should have received a copy of the MIT License and the GNU General Public License
 * along with Côtehaus.  If not, see <https://opensource.org/licenses/MIT> and <http://www.gnu.org/licenses/>.
 */
%{
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include "composer.h"
#include "context.h"
#include "lgwseq.h"
#include "parse_file.h"
#include "type_id.h"
#include "types.h"
#include "unresolved_type.h"
// bool modifier_list_flag=false;  // yylex use case: if(modifier_list_flag && ++c%2) return SEMANTICLESS;  // c starts in 0
struct type_id_st *typ_id;
%}
%union {
	struct class_def_st *class_def;
	lgwseq_t* basic_type;
	lgwseq_t ident;
	lgwseq_t *string_literal;
	struct token_list_st *token_list;
	struct list_head list_head;
	struct str_id_st *str_id;
	struct type_id_st *type_id;
	struct method_id_st *method_id;
	struct field_id_st *field_id;
	struct type_list_st *type_list;
	struct formal_params_st {
		struct type_list_st *type_list;
		struct token_list_st *identifier_list;
	} formal_params;
	struct method_rest_st {
		struct formal_params_st formal_params;
		struct type_list_st *throws_list;
		int array_dimensions;
		void *block;
	} method_rest;
	struct list_head variable_head;
	struct {
		enum { Field, Method} type;
		union {
			struct method_rest_st method_rest;
			struct list_head variable_head;
		} rest;
	} method_or_field_rest;
}
%start CompilationUnit
%token-table
%token BooleanLiteral
%token CharacterLiteral
%token FloatingPointLiteral
%token IntegerLiteral
%token NullLiteral
%token <string_literal>StringLiteral
%token <ident> Identifier
%token END 0 "end of file"
// %token SEMANTICLESS   // Precludes noisy warnings for the output to read cleaner.
%token IMPLEMENTATION_ELISION
%type <class_def> NormalClassDeclaration
%type <type_id> Type
%type <type_list> TypeList
%type <token_list> ReferenceType
%type <method_or_field_rest> MethodOrFieldRest
%type <method_rest> MethodDeclaratorRest
%type <variable_head> FieldDeclaratorsRest
%type <formal_params> FormalParameters
%type <basic_type> BasicType
%type <ident> IdentifierMaybeQualified

%initial-action
{
	struct top_code_st *top_code=init_top_code();
	add_import(add_ident(for_lgwseq(L"lang",4),init_ident(for_lgwseq(L"java",4))),reftype_glob_import, top_code);
	struct context_st *context = get_context(top_code);
}

%%
IdentifierMaybeQualified:
	Identifier  { $$=init_ident($1); }
	| IdentifierMaybeQualified '.' Identifier  { $$=add_ident($3, $1);} 
	;
	
IdentifierMaybeQualifiedList:
	IdentifierMaybeQualified
	| IdentifierMaybeQualifiedList ',' IdentifierMaybeQualified
	;

CompilationUnit:
	/*empty*/
	| ImportDeclarationList
	| ImportDeclarationList TypeDeclarationList /* { set_package(init_ident(for_lgwseq(L"",0)), top_code); } */
	| TypeDeclarationList
	| Annotations "package" IdentifierMaybeQualified ';'
		{ set_package($3, top_code); }
	| "package" IdentifierMaybeQualified ';'
		{ set_package($2, top_code); }
	| Annotations "package" IdentifierMaybeQualified ';' ImportDeclarationList
	| "package" IdentifierMaybeQualified ';' ImportDeclarationList
		{ set_package($2, top_code); }
	| Annotations "package" IdentifierMaybeQualified ';' ImportDeclarationList TypeDeclarationList
	| "package" IdentifierMaybeQualified ';' ImportDeclarationList TypeDeclarationList
		{ set_package($2, top_code); }
	| Annotations "package" IdentifierMaybeQualified ';' TypeDeclarationList
		{ set_package($3, top_code); }
	| "package" IdentifierMaybeQualified ';'  TypeDeclarationList
		{ set_package($2, top_code); }  
	;

ImportDeclarationList:
	ImportDeclaration
	| ImportDeclarationList ImportDeclaration
	;
	
TypeDeclarationList:
	TypeDeclaration
	| TypeDeclarationList TypeDeclaration
	;
	
ImportDeclaration:
	"import" "static" IdentifierMaybeQualified '.' '*' ';'
		{ add_import($3, member_glob_import, *top_code); }
	| "import" "static" IdentifierMaybeQualified ';'
		{ add_import($3, member_import, *top_code); }
	| "import" IdentifierMaybeQualified '.' '*' ';' 
		{ add_import($2, reftyp_glob_import, *top_code); }
	| "import"  IdentifierMaybeQualified ';'
		{ add_import($2, reftyp_import, *top_code); }
	;

TypeDeclaration:
	ClassOrInterfaceDeclaration
	| ';'
	;

ClassOrInterfaceDeclaration:
	InterfaceDeclaration
	| ClassDeclaration
	| ModifierList InterfaceDeclaration
	| ModifierList  ClassDeclaration 
	;

ClassDeclaration:
	NormalClassDeclaration
	| EnumDeclaration
	;

InterfaceDeclaration:
	NormalInterfaceDeclaration
	| AnnotationTypeDeclaration
	;

NormalClassDeclaration:
	"class" Identifier    ClassBody  { $$ = malloc(struct class_def); }
	| "class" Identifier   "implements" TypeList ClassBody  { $$ = malloc(struct class_def); }
	| "class" Identifier  "extends" ReferenceType  ClassBody  { $$ = malloc(struct class_def); }
	| "class" Identifier "extends" ReferenceType "implements" TypeList ClassBody
	{
		struct class_def_st *class_def = add_class_def(/* clstyp */ add_type_id(add_str_id($2)), PARSING_EXTERN_DECL); 
		add_unresolved_type($4, context,/*resolution_method*/type_id_ptr_ptr_method,/*method_parameter*/&class_def->parenttyp);   // pin to class_def's parenttyp to be resolved later
		EXPAND_MULTICALL(add_unresolved_type($6, context,/*resolution_method*/type_id_ptr_ptr_method,/*method_parameter*/&class_def->parenttyp));   // pin to class_def's parenttyp to be resolved later
		class_def->parent_iface = $6;
		class_def->clsstyp->cotehaus_class_def=class_def;
		add_referential($2,context);
	}
	| "class" Identifier TypeParameters   ClassBody  { $$ = malloc(struct class_def); }
	| "class" Identifier TypeParameters  "implements" TypeList ClassBody  { $$ = malloc(struct class_def); }
	| "class" Identifier TypeParameters "extends" Type  ClassBody  { $$ = malloc(struct class_def); }
	| "class" Identifier TypeParameters "extends" Type "implements" TypeList ClassBody  { $$ = malloc(struct class_def); }
	;

EnumDeclaration:
	"enum" Identifier  EnumBody
	| "enum" Identifier "implements" TypeList EnumBody
	;

NormalInterfaceDeclaration:
	"interface" Identifier   InterfaceBody
	| "interface" Identifier  "extends" TypeList InterfaceBody
	| "interface" Identifier TypeParameters  InterfaceBody
	| "interface" Identifier TypeParameters "extends" TypeList InterfaceBody
	;

AnnotationTypeDeclaration:
	'@' "interface" Identifier AnnotationTypeBody
	;

Type:
	BasicType { $$ = add_type_id($1); }
	| BasicType ArrayDesignatorList { $$ = add_type_id($1); }
	| ReferenceType  { $$ = malloc(sizeof struct type_id_st); add_unresolved_type($1, context_peek()->search_context_item_head, $$); }
	| ReferenceType ArrayDesignatorList { $$ = malloc(sizeof struct type_id_st); add_unresolved_type($1, context_peek()->search_context_item_head, $$); }
	;

BasicType:
	"byte" { $$=for_lgwseq(1, L"B");}
	| "short" { $$=for_lgwseq(1, L"S");}
	| "char" { $$=for_lgwseq(1, L"C");}
	| "int" { $$=for_lgwseq(1, L"I");}
	| "long" { $$=for_lgwseq(1, L"J");}
	| "float" { $$=for_lgwseq(1, L"F");}
	| "double" { $$=for_lgwseq(1, L"D");}
	| "boolean" { $$=for_lgwseq(1, L"Z");}
	;

ReferenceType:
	IdentifierMaybeQualified
	| IdentifierMaybeQualified TypeArguments 
	;

TypeArguments:
	'<' TypeArgumentList '>'
	;

TypeArgument:
	ReferenceType
	| '?' 
	| '?'   "super" ReferenceType 
	| '?'  "extends"  ReferenceType 
	;

NonWildcardTypeArguments:
	'<' TypeList '>'
	;

TypeList:
	ReferenceType { $$ = *add_type_list(); struct type_id_st *type_id = malloc(sizeof struct type_id_st); add_type_member($$, type_id); add_unresolved_type($1, context_peek()->search_context_item_head, &type_id); }
	| TypeList ',' ReferenceType
	;

TypeArgumentsOrDiamond:
	'<' '>'
	| TypeArguments
	;

NonWildcardTypeArgumentsOrDiamond:
	'<' '>'
	| NonWildcardTypeArguments
	;

TypeParameters:
	'<' TypeParameterList '>'
	;

TypeParameter:
	Identifier 
	| Identifier "extends" Bound
	;

Bound:
	ReferenceType 
	| Bound '&' ReferenceType
	;

Modifier:
	Annotation
	| "public" { $$=public_mod }
	| "protected" { $$=protected_mod }
	| "private" { $$=private_mod }
	| "static" { $$=static_mod }
	| "abstract" { $$=abstract_mod }
	| "final" { $$=final_mod }
	| "native" { $$=native_mod }
	| "synchronized" { $$=synchronized_mod }
	| "transient" { $$=transient_mod }
	| "volatile" { $$=volatile_mod }
	| "strictfp" { $$=strictfp_mod }
	;

Annotations:
	Annotation 
	| Annotations Annotation
	;

Annotation:
	'@' IdentifierMaybeQualified 
	| '@' IdentifierMaybeQualified '('  ')'
	| '@' IdentifierMaybeQualified '(' AnnotationElement ')'
	;

AnnotationElement:
	ElementValuePairs
	| ElementValue
	;

ElementValuePairs:
	ElementValuePair 
	| ElementValuePairs ',' ElementValuePair
	;

ElementValuePair:
	Identifier '=' ElementValue
	;

ElementValue:
	Annotation
	| Expression1
	| ElementValueArrayInitializer
	;

ElementValueArrayInitializer:
	'{' ElementValuesList '}'
	;

ClassBody:
	'{'  '}'
	| '{' ClassBodyDeclarationList '}'
	;

ClassBodyDeclaration:
	';'
	| MemberDecl
	| ModifierList  MemberDecl
	| Block
	| "static" Block
	;

MemberDecl:
	MethodOrFieldDecl
	| "void" Identifier VoidMethodDeclaratorRest
	| Identifier ConstructorDeclaratorRest
	| GenericMethodOrConstructorDecl
	| ClassDeclaration
	| InterfaceDeclaration
	;

MethodOrFieldDecl:
	Type Identifier MethodOrFieldRest
	{
		switch($3.type) {
			case Method:
				add_method_id(context_peek()->enclosing_class, add_proto_id($1, $3.rest.method_rest.formal_params->type_list),$2);
			break;
			case Field:
				add_field_id(context_peek()->enclosing_class, $1, add_str_id($2));   // TODO add_field_id
	// Should other variable_decl's be beard in MethodOrFieldRest
	struct variable_decl_st *variable_decl;
				list_for_each_entry(variable_decl, struct variable_decl_st, variable_decl_list, &$3.variable_head)
					add_field_id(context_peek()->enclosing_class, $1, add_str_id(variable_decl->name));
			break;
		}
	}
	;

MethodOrFieldRest:
	FieldDeclaratorsRest ';' { $$.type= Field; }
	| MethodDeclaratorRest   { $$.type= Method; }
	;

FieldDeclaratorsRest:
	VariableDeclaratorRest 
	| VariableDeclaratorRest VariableDeclaratorList
	;

MethodDeclaratorRest:
	FormalParameters    ';' { $$.formal_params = $1; }
	| FormalParameters   Block
	| FormalParameters  "throws" IdentifierMaybeQualifiedList  ';'
	| FormalParameters  "throws" IdentifierMaybeQualifiedList Block 
	| FormalParameters ArrayDesignatorList   ';'
	| FormalParameters ArrayDesignatorList  Block 
	| FormalParameters ArrayDesignatorList "throws" IdentifierMaybeQualifiedList  ';'
	| FormalParameters ArrayDesignatorList "throws" IdentifierMaybeQualifiedList Block 
	;

VoidMethodDeclaratorRest:
	FormalParameters   ';'
	| FormalParameters  Block 
	| FormalParameters "throws" IdentifierMaybeQualifiedList  ';'
	| FormalParameters "throws" IdentifierMaybeQualifiedList Block 
	;

ConstructorDeclaratorRest:
	FormalParameters  Block
	| FormalParameters "throws" IdentifierMaybeQualifiedList Block
	| FormalParameters  IMPLEMENTATION_ELISION ';'
	| FormalParameters "throws" IdentifierMaybeQualifiedList IMPLEMENTATION_ELISION ';'
	;

GenericMethodOrConstructorDecl:
	TypeParameters GenericMethodOrConstructorRest
	;

GenericMethodOrConstructorRest:
	 "void" Identifier VoidMethodDeclaratorRest
	| Type  Identifier MethodDeclaratorRest
	| Identifier ConstructorDeclaratorRest
	;

InterfaceBody:
	'{'  '}'
	| '{' InterfaceBodyDeclarationList '}'
	;

InterfaceBodyDeclaration:
	';'
	| InterfaceMemberDecl
	| ModifierList  InterfaceMemberDecl
	;

InterfaceMemberDecl:
	InterfaceMethodOrFieldDecl
	| "void" Identifier VoidInterfaceMethodDeclaratorRest
	| InterfaceGenericMethodDecl
	| ClassDeclaration
	| InterfaceDeclaration
	;

InterfaceMethodOrFieldDecl:
	Type Identifier InterfaceMethodOrFieldRest
	;

InterfaceMethodOrFieldRest:
	ConstantDeclaratorsRest ';' /* Like FieldDeclaratorsRest, but initializers have a compulsory "'=' value" */
	| InterfaceMethodDeclaratorRest
	;

ConstantDeclaratorsRest:
	ConstantDeclaratorRest 
	| ConstantDeclaratorRest ConstantDeclaratorList
	;

ConstantDeclaratorRest:
	 '=' VariableInitializer
	| ArrayDesignatorList '=' VariableInitializer
	;

ConstantDeclaratorList:
	',' ConstantDeclarator
	| ConstantDeclaratorList ',' ConstantDeclarator
	;

ConstantDeclarator:
	Identifier ConstantDeclaratorRest
	;

InterfaceMethodDeclaratorRest:
	FormalParameters   ';'
	| FormalParameters  "throws" IdentifierMaybeQualifiedList ';'
	| FormalParameters ArrayDesignatorList  ';'
	| FormalParameters ArrayDesignatorList "throws" IdentifierMaybeQualifiedList ';'
	;

VoidInterfaceMethodDeclaratorRest:
	FormalParameters  ';'
	| FormalParameters "throws" IdentifierMaybeQualifiedList ';'
	;

InterfaceGenericMethodDecl:
	TypeParameters  "void" Identifier VoidInterfaceMethodDeclaratorRest
	| TypeParameters Type  Identifier InterfaceMethodDeclaratorRest
	;

FormalParameters:
	'('  ')'
	| '(' FormalParameterDecls ')'  { $$.type_list= add_type_list();/* TODO $$.identifier_list=the names of the parameter decls*/ }
	;

FormalParameterDecls:
	 Type FormalParameterDeclsRest { add_type_member($1);}
	| VariableModifierList Type FormalParameterDeclsRest { add_type_member($2);}
	;

VariableModifier:
	"final"
	| Annotation
	;

FormalParameterDeclsRest:
	VariableDeclaratorId 
	| VariableDeclaratorId ',' FormalParameterDecls
	| "..." VariableDeclaratorId
	;

VariableDeclaratorId:
	Identifier 
	| Identifier ArrayDesignatorList
	;

VariableDeclarators:
	VariableDeclarator
	| VariableDeclarator VariableDeclaratorList
	;

VariableDeclarator:
	Identifier VariableDeclaratorRest
	;

VariableDeclaratorRest:
	/*empty*/ 
	| '=' VariableInitializer 
	| ArrayDesignatorList 
	| ArrayDesignatorList  '=' VariableInitializer 
	;

VariableInitializer:
	ArrayInitializer
	| Expression
	;

ArrayInitializer:
	'{'  '}'
	| '{'  VariableInitializer    '}'
	| '{'  VariableInitializer  ','  '}'
	| '{'  VariableInitializer VariableInitializerList   '}'
	| '{'  VariableInitializer VariableInitializerList ','  '}'
	;

Block:
	'{' { context=open_context(context) }
	BlockStatements '}' { context=close_context(context) }
	;

BlockStatements:
	/*empty*/
	| BlockStatementList
	;

BlockStatement:
	LocalVariableDeclarationStatement
	| ClassOrInterfaceDeclaration
	| Statement
	| Identifier ':' Statement
	;

LocalVariableDeclarationStatement:
	Type VariableDeclarators ';'
	| VariableModifierList Type VariableDeclarators ';'
	;

Statement:
	Block
	| ';'
	| Identifier ':' Statement
	| StatementExpression ';'
	| "if" ParExpression Statement 
	| "if" ParExpression Statement "else" Statement
	| "assert" Expression  ';'
	| "assert" Expression ':' Expression ';'
	| "switch" ParExpression '{' SwitchBlockStatementGroups '}'
	| "while" ParExpression Statement
	| "do" Statement "while" ParExpression ';'
	| "for" '(' ForControl ')' Statement
	| "break"  ';'
	| "break" Identifier ';'
	| "continue"  ';'
	| "continue" Identifier ';'
	| "return"  ';'
	| "return" Expression ';'
	| "throw" Expression ';'
	| "synchronized" ParExpression Block
	| "try" Block   Finally
	| "try" Block Catches 
	| "try" Block  Catches Finally
	| "try" ResourceSpecification Block  
	| "try" ResourceSpecification Block  Finally
	| "try" ResourceSpecification Block Catches 
	| "try" ResourceSpecification Block Catches Finally
	;

StatementExpression:
	Expression
	;

Catches:
	CatchClause 
	| Catches CatchClause
	;

CatchClause:
	"catch" '('  CatchType Identifier ')' Block
	| "catch" '(' VariableModifierList CatchType Identifier ')' Block
	;

CatchType:
	IdentifierMaybeQualified 
	| IdentifierMaybeQualified PipeSeparatedIdentifierMaybeQualifiedList
	;

Finally:
	"finally" Block
	;

ResourceSpecification:
	'(' Resources  ')'
	| '(' Resources ';' ')'
	;

Resources:
	Resource 
	| Resources ';' Resource
	;

Resource:
	ReferenceType VariableDeclaratorId '=' Expression
	| VariableModifierList ReferenceType VariableDeclaratorId '=' Expression
	;

SwitchBlockStatementGroups:
	/*empty*/
	| SwitchBlockStatementGroupList
	;

SwitchBlockStatementGroup:
	SwitchLabels BlockStatements
	;

SwitchLabels:
	SwitchLabel 
	| SwitchLabels SwitchLabel
	;

SwitchLabel:
	"case" Expression ':'
//  | "case" EnumConstantName ':'  //TODO add a new search_entry type=STATIC_MEMBER which will allow to search to references to static members. Add a new search_context_item type=STATIC_IMPORT to allow to allow "import static" and "import QualifiedEnumConstantName" to occur in the search context.
	| "default" ':'
	;

//EnumConstantName:
//  Identifier
//  ;

ForControl:
	ForVarControl
	| ForInit ';'  ';' 
	| ForInit ';'  ';' ForUpdate
	| ForInit ';' Expression ';' 
	| ForInit ';' Expression ';' ForUpdate
	;

ForVarControl:
	 Type VariableDeclaratorId ForVarControlRest
	| VariableModifierList Type VariableDeclaratorId ForVarControlRest
	;

ForVarControlRest:
	ForVariableDeclaratorsRest ';'  ';' 
	| ForVariableDeclaratorsRest ';'  ';' ForUpdate
	| ForVariableDeclaratorsRest ';' Expression ';' 
	| ForVariableDeclaratorsRest ';' Expression ';' ForUpdate
	| ':' Expression
	;

ForVariableDeclaratorsRest:
	/*empty*/ 
	| '=' VariableInitializer 
	| VariableDeclaratorList
	| '=' VariableInitializer VariableDeclaratorList
	;

ForInit:
	ForUpdate
	;

ForUpdate:
	StatementExpression 
	| ForUpdate ',' StatementExpression
	;

Expression:
	Expression1 
	| Expression1 AssignmentOperator Expression1
	;

AssignmentOperator:
	'='
	| "+="
	| "-="
	| "*="
	| "/="
	| "&="
	| "|="
	| "^="
	| "%="
	| "<<="
	| ">>="
	| ">>>="
	;

Expression1:
	Expression2 
	| Expression2 Expression1Rest
	;

Expression1Rest:
	'?' Expression ':' Expression1
	;

Expression2:
	Expression3 
	| Expression3 Expression2Rest
	;

Expression2Rest:
	//  empty alternative suppressed because both covered by and conflicting with Expression2: Expression3 
	InfixOpExpression3List
	| "instanceof" Type
	;

InfixOp:
	"||"
	| "&&"
	| '|'
	| '^'
	| '&'
	| "=="
	| "!="
	| '<'
	| '>'
	| "<="
	| ">="
	| "<<"
	| ">>"
	| ">>>"
	| '+'
	| '-'
	| '*'
	| '/'
	| '%'
	;

Expression3:
	PrefixOp Expression3
	| '('  Type ')'  Expression3
	| '(' Expression  ')'  Expression3
	| Primary  
	| Primary SelectorList 
	| Primary  PostfixOpList
	| Primary SelectorList PostfixOpList
	;

PrefixOp:
	"++"
	| "--"
	| '!'
	| '~'
	| '+'
	| '-'
	;

PostfixOp:
	"++"
	| "--"
	;

Primary:
	Literal
	| ParExpression
	| "this" 
	| "this" Arguments
	| "super" SuperSuffix
	| "new" Creator
	| NonWildcardTypeArguments  "this" Arguments
	| NonWildcardTypeArguments ExplicitGenericInvocationSuffix 
	| Identifier  IdentifierSuffix
	| IdentifierMaybeQualified
	| IdentifierMaybeQualified IdentifierSuffix
	| BasicType  '.' "class"
	| BasicType ArrayDesignatorList '.' "class"
	| "void" '.' "class"
	;

Literal:
	IntegerLiteral
	| FloatingPointLiteral
	| CharacterLiteral
	| StringLiteral
	| BooleanLiteral
	| NullLiteral
	;

ParExpression:
	'(' Expression ')'
	;

Arguments:
	'('  ')'
	| '('  Expression   ')'
	| '('  Expression ExpressionList  ')'
	;

SuperSuffix:
	Arguments
	| '.' Identifier 
	| '.' Identifier Arguments
	;

ExplicitGenericInvocationSuffix:
	"super" SuperSuffix
	| Identifier Arguments
	;

Creator:
	NonWildcardTypeArguments CreatedName ClassCreatorRest
	| CreatedName  ArrayCreatorRest
	| CreatedName ClassCreatorRest 
	;

CreatedName:
	Identifier  
	| Identifier TypeArgumentsOrDiamond 
	| Identifier  DiamondKindIdentifierList
	| Identifier TypeArgumentsOrDiamond DiamondKindIdentifierList
	;

ClassCreatorRest:
	Arguments 
	| Arguments ClassBody
	;

ArrayCreatorRest:
	'['  Expression ']'  
	| '[' ']'  ArrayInitializer 
	| '['  Expression ']'  ArrayDesignatorList
	| '[' ']' ArrayDesignatorList ArrayInitializer 
	| '['  Expression ']' SubscriptExpressionList 
	| '['  Expression ']' SubscriptExpressionList ArrayDesignatorList
	;

IdentifierSuffix:
	'['  Expression ']'
	| '['  '.' "class"  ']'
	| '[' ArrayDesignatorList '.' "class"  ']'
	| Arguments
	| '.'  "new"  InnerCreator
	| '.'  "super" Arguments 
	| '.'  "this" 
	| '.'  ExplicitGenericInvocation 
	| '.' "class" 
	| '.'  "new" NonWildcardTypeArguments InnerCreator
	;

ExplicitGenericInvocation:
	NonWildcardTypeArguments ExplicitGenericInvocationSuffix
	;

InnerCreator:
	Identifier  ClassCreatorRest
	| Identifier NonWildcardTypeArgumentsOrDiamond ClassCreatorRest
	;

Selector:
	'.' Identifier 
	| '.' Identifier Arguments
	| '.' ExplicitGenericInvocation
	| '.' "this"
	| '.' "super" SuperSuffix
	| '.' "new"  InnerCreator
	| '.' "new" NonWildcardTypeArguments InnerCreator
	| '[' Expression ']'
	;

EnumBody:
	'{'    '}'
	| '{'   EnumBodyDeclarations '}'
	| '{'  ','  '}'
	| '{'  ',' EnumBodyDeclarations '}'
	| '{' EnumConstants   '}'
	| '{' EnumConstants  EnumBodyDeclarations '}'
	| '{' EnumConstants ','  '}'
	| '{' EnumConstants ',' EnumBodyDeclarations '}'
	;

EnumConstants:
	EnumConstant
	| EnumConstants ',' EnumConstant
	;

EnumConstant:
	Identifier
	| Identifier  ClassBody
	| Identifier Arguments 
	| Identifier Arguments ClassBody
	| Annotations Identifier
	| Annotations Identifier  ClassBody
	| Annotations Identifier Arguments 
	| Annotations Identifier Arguments ClassBody
	;

EnumBodyDeclarations:
	';' 
	| ';' ClassBodyDeclarationList
	;

AnnotationTypeBody:
	'{'  '}'
	| '{' AnnotationTypeElementDeclarations '}'
	;

AnnotationTypeElementDeclarations:
	AnnotationTypeElementDeclaration
	| AnnotationTypeElementDeclarations AnnotationTypeElementDeclaration
	;

AnnotationTypeElementDeclaration:
	 AnnotationTypeElementRest
	| ModifierList AnnotationTypeElementRest
	;

AnnotationTypeElementRest:
	Type Identifier AnnotationMethodOrConstantRest ';'
	| ClassDeclaration
	| InterfaceDeclaration
/*| EnumDeclaration  // suppressed because both comprehended in and conflicting with ClassDeclaration */
/*| AnnotationTypeDeclaration  // suppressed because both comprehended in and conflicting with InterfaceDeclaration */
	;

AnnotationMethodOrConstantRest:
	AnnotationMethodRest
	| ConstantDeclaratorsRest
	;

AnnotationMethodRest:
	'(' ')'  
	| '(' ')'  "default" ElementValue
	| '(' ')' '[' ']' 
	| '(' ')' '[' ']' "default" ElementValue

PostfixOpList:
	PostfixOp
	| PostfixOpList PostfixOp
	;

ClassBodyDeclarationList:
	ClassBodyDeclaration
	| ClassBodyDeclarationList ClassBodyDeclaration
	;

PipeSeparatedIdentifierMaybeQualifiedList:
	'|' IdentifierMaybeQualified
	| PipeSeparatedIdentifierMaybeQualifiedList '|' IdentifierMaybeQualified
	;

VariableModifierList:
	VariableModifier
	| VariableModifierList VariableModifier
	;

VariableDeclaratorList:
	',' VariableDeclarator
	| VariableDeclaratorList ',' VariableDeclarator
	;

SubscriptExpressionList:
	'[' Expression ']'
	| SubscriptExpressionList '[' Expression ']'
	;

TypeArgumentList:
	TypeArgument
	| TypeArgumentList ',' TypeArgument
	;

InterfaceBodyDeclarationList:
	InterfaceBodyDeclaration
	| InterfaceBodyDeclarationList InterfaceBodyDeclaration
	;

ExpressionList:
	',' Expression
	| ExpressionList ',' Expression
	;

SelectorList:
	Selector
	| SelectorList Selector
	;

TypeParameterList:
	TypeParameter
	| TypeParameterList ',' TypeParameter
	;

ModifierList:
	Modifier
	| ModifierList Modifier
	;

VariableInitializerList:
	',' VariableInitializer
	| VariableInitializerList ',' VariableInitializer
	;

ElementValuesList:
	','
	| ElementValue
	| ElementValuesList  ','
	| ElementValuesList ElementValue
	;

SwitchBlockStatementGroupList:
	SwitchBlockStatementGroup
	| SwitchBlockStatementGroupList SwitchBlockStatementGroup
	;

BlockStatementList:
	BlockStatement
	| BlockStatementList BlockStatement
	;

ArrayDesignatorList:
	'[' ']'
	| ArrayDesignatorList '[' ']'
	;

InfixOpExpression3List:
	InfixOp Expression3
	| InfixOpExpression3List InfixOp Expression3
	;

DiamondKindIdentifierList:
	'.' Identifier 
	| '.' Identifier TypeArgumentsOrDiamond
	| DiamondKindIdentifierList '.' Identifier 
	| DiamondKindIdentifierList '.' Identifier TypeArgumentsOrDiamond
	;
%%
#include "wtname.h"
int
wtname_lookup(const wchar_t *ptr, size_t len) {
	// Adapted from a code borrowed from Bison's manual
	int i;
	for (i = 0; i != YYNTOKENS; i++)
	{
		if (wtname[i] != 0
		&& ! wcsncmp (&wtname[i][1], ptr,
		len)
		&& wtname[i][len + 2] == L'\0')
			break;
	}
	return i==YYNTOKENS?-1:mytoknum[i];
}

void
yyerror (char const *s)
{
	fprintf (stderr, "%s\n", s);
}
